#include <drivers.h>

/* 注册一个设备 */
err_t device_register(struct device *dev, const char *name, const uint16_t flag)
{
    dev->parent.type = CLASS_TYPE_DEVICE;
    object_init(&dev->parent, name);

	assert(dev != NULL);

    dev->flag = DEVICE_FLAG_INIT | flag;
    dev->ref_count = 0;

    return 0;
}

/* 取消注册一个设备 */
err_t device_unregister(struct device *dev)
{
    assert(dev != NULL);

    object_deinit(&dev->parent);

    dev->flag = DEVICE_FLAG_CLOSE;

	return 0;
}

/* 通过名字查找一个设备 */
struct device *device_find(const char *name)
{
    return (struct device *)object_find(name, CLASS_TYPE_DEVICE);
}

/* 初始化一个设备 */
err_t device_init(struct device *dev)
{
    err_t ret = 0;

	assert(dev != NULL);

    if (dev->ops->init != NULL) {
        ret = dev->ops->init(dev);
        if (ret < 0)
            return ret;
    }
    dev->flag |= DEVICE_FLAG_ACTIVATED;

    return 0;
}

/* 打开一个设备 */
err_t device_open(struct device *dev, uint16_t oflag)
{
	err_t ret = 0;

	assert(dev != NULL);

	dev->oflag = oflag;

	/* 如果这个设备还没有初始化，则先初始化这个设备 */
	if (!(dev->flag & DEVICE_FLAG_ACTIVATED)) {
		if (dev->ops->init != NULL) {
            ret = dev->ops->init(dev);
            if (ret < 0)
                return ret;
        }
		dev->flag |= DEVICE_FLAG_ACTIVATED;
    }

    /* 如果设备已经打开了并且这个设备只能被打开一次，则退出 */
	if (dev->flag & DEVICE_FLAG_OPEN && dev->flag & DEVICE_FLAG_STANDALONE)
        return -1;

	/* 如果这个设备定义了open方法则执行open方法 */
	if (dev->ops->open != NULL) {
        ret = dev->ops->open(dev, oflag);
        if (ret < 0)
            return ret;
    }
	/* 将打开次数计数加1 */
	dev->ref_count++;
	dev->flag |= DEVICE_FLAG_OPEN;

	return 0;
}

/* 关闭一个设备 */
err_t device_close(struct device *dev)
{
    err_t ret = 0;

	assert(dev != NULL);

    /* 如果这个设备没有被打开，或者打开计数小于0则直接退出 */
    if (!(dev->flag & DEVICE_FLAG_OPEN) || dev->ref_count <= 0)
        return -EIO;


    dev->ref_count--;

    /* 如果打开计数小于等于零，则说明设备确实被关闭了 */
	if (dev->ref_count <= 0) {
		dev->flag = DEVICE_FLAG_CLOSE;

        if (dev->ops->close != NULL) {
            ret = dev->ops->close(dev);
            if (ret < 0)
                return ret;
        }
	}

    return 0;
}

/* 控制一个设备 */
err_t device_control(struct device *dev, int cmd, void *args)
{
	err_t ret = 0;

	assert(dev != NULL);

	/* 如果这个设备没有被打开则直接退出 */
	if (!(dev->flag & DEVICE_FLAG_OPEN))
		return -EIO;

	if (dev->ops->control != NULL) {
		ret = dev->ops->control(dev, cmd, args);
		if (ret < 0)
			return ret;
	}

	return 0;
}

/* 写一个设备 */
size_t device_write(struct device *dev, const size_t offset, const void *user_buffer, const size_t size)
{
	size_t ret;

	assert(dev != NULL);

	if (!(dev->flag & DEVICE_FLAG_OPEN))
		return 0;

	if (dev->ops->write == NULL)
		return 0;

	ret = dev->ops->write(dev, offset, user_buffer, size);

	return ret;
}

/* 读一个设备 */
size_t device_read(struct device *dev, const size_t offset, void *user_buffer, const size_t size)
{
	size_t ret;

	assert(dev != NULL);

	if (!(dev->flag & DEVICE_FLAG_OPEN))
		return 0;

	if (dev->ops->read == NULL)
		return 0;

	ret = dev->ops->read(dev, offset, user_buffer, size);

	return ret;
}

/* 设置接收回调函数 */
err_t device_set_rx_indicate(struct device *dev,
                             err_t (*rx_ind)(struct device *dev,
                             size_t size))
{
	assert(dev != NULL);

	dev->rx_indicate = rx_ind;

	return 0;
}

/* 设置发送回调函数 */
err_t device_set_tx_complete(struct device *dev,
                                   err_t (*tx_done)(struct device *dev,
                                   void *buffer))
{
	assert(dev != NULL);

	dev->tx_complete = tx_done;

	return 0;
}
